#!/usr/bin/env python
# -*- coding: utf-8 -*-
import random
import time
import numpy as NP
import utility.utility as UTL
from data.Data import *

class Centroids():
	'''
	Classe per la gestione dei centroidi
	'''
		
	def __init__(self,nCentr,nDat,X):
		'''
		Inizializza i centroidi con punti presi a 
		caso dai dal set di dati
		'''
		self.nCentr = nCentr
		 		
		self.nDat = nDat
		
		self.k = range(self.nCentr)
	
		for i in range(self.nCentr):
			
			self.k[i] = Data()
			
			List = random.sample(xrange(self.nDat-1),1)
			idx = List[0]
			
			self.k[i].x =  X[idx].x	
			self.k[i].y =  X[idx].y
			
	def get_centroids(self):
		
		return self.k
		
	def printData(self):
		'''
		Stampa a video le coordinate dei centroidi
		'''
		for i in range(self.nCentr):
			
			self.k[i].printData()
			
	def voronoi(self,X):
		'''
		calcola il voronoi-set di self
		'''
		
		self.pi = range(self.nCentr)
		for i in range(self.nCentr):
			self.pi[i] = range(self.nDat)
			
		### Apparteneza dell'oggetto j al cluster i
		### calcolo della norma euclidea tra centroide e punto
		### per tutti i centroidi e per tutti i punti
		
		for j in range(self.nDat):
			for i in range(self.nCentr):
						
				self.pi[i][j] = UTL.norma(X[j],self.k[i])
		
	def get_voronoi(self):
		'''
		Ritorna il voronoi set
		'''
		return self.pi
		
	def bestMatch(self):
		'''
		Suddivide i punti associandoli con il nodo piu' vicino a loro
		cerca tra i centroidi quello che ha la minor distanza dal punto.
		'''
		self.w = NP.zeros((self.nCentr,self.nDat))
		
		for j in range(self.nDat):			
			distance = []
			for i in range(self.nCentr):
				distance.append(self.pi[i][j])
			minDist = min(distance)
			minIndx = distance.index(minDist)
			self.w[minIndx][j] = 1
		
	def get_bestMatch(self):
		'''
		Ritorna la matrice di best match
		'''	
		return self.w
		
	def print_w(self):
		'''
		stampa a video la matrice w
		'''
		
		for i in range(self.nCentr):
			for j in range(self.nDat):
				print self.w[i][j] , " ",
			print "|"
				

	def setCentroidToPoint(self,X):
		'''
		Metodo che data la matrice di appartenenza w associa il 
		punto al centroide di appartenenza
		'''
		
		for j in range(self.nDat):
			for i in range(self.nCentr):
				
				if(self.w[i][j] == 1):
					X[j].clust = i
					
	def updateCentroidsPosition(self,X):
		'''
		Aggiorna la posizione dei centroidi K-Means
		'''
		centr = range(self.nCentr)
		nCentr = NP.zeros(self.nCentr)
		
		for i in range(self.nCentr):
			centr[i] = []
			
		for i in range(self.nDat):
			centr[X[i].clust].append(X[i])
			nCentr[X[i].clust] += 1
		
		### Utilizzo il k-mean per avvicinami al baricentro dei punti
		for i in range(self.nCentr):
			if(nCentr[i] != 0):
				xNew, yNew = UTL.K_Means(centr[i],nCentr[i])
				self.k[i].x =  xNew 
				self.k[i].y =  yNew
			else:
				### TODO: Caso in cui il centroide non è il + vicino di nessuno.
				### DA togliere !!!
				 
				if(random.random() < 0.5):
					self.k[i].x += 0.01 *random.random()  
					self.k[i].y += 0.01 *random.random()
				else:
					self.k[i].x -= 0.01 *random.random()  
					self.k[i].y -= 0.01 *random.random()
					
		
	def stop(self,Vold):
		'''
		Valuta la condizione di stop
		'''
		count = 0
		   
		for i in range(self.nCentr):
			if(not(self.k[i].x == Vold[i].x and self.k[i].y == Vold[i].y)):
				
				count += 1
				
		if(count == 0): return 1
		else: return 0
